﻿#ifndef DLLLOADER_H
#define DLLLOADER_H

#include <string>
#ifdef _WIN32
#include <windows.h>  
#define DLL_SUFFIX L".dll"
#else 
#include <dlfcn.h>  
typedef void *  HMODULE;
#define DLL_SUFFIX L".so"
#endif  


class CDllLoader
{
public:
	CDllLoader()
	{
		m_hModule = NULL;
	}
	~CDllLoader()
	{
		gdl_Close(m_hModule);
	}
	inline bool Open(std::string lpname)
	{
		m_strDllName = lpname;  
		m_hModule = gdl_Open(m_strDllName.c_str());
		return m_hModule != NULL;
	}
	inline void *GetProc(const char *pfname)
	{
		return gdl_GetProc(m_hModule, pfname);
	}

	const char *GetLastErrorMsg()
	{
		char msg[100] = { 0 };
		gdl_GetLastErrorMsg(msg, 99);
		m_strMsg = msg;
		return m_strMsg.c_str();
	}

	std::wstring WGetLastErrorMsg()
	{
		char msg[100] = { 0 };
		gdl_GetLastErrorMsg(msg, 99);

		return StringToWString(msg);
	}


protected:

	std::wstring StringToWString(const std::string &str)
	{
	    std::wstring wstr(str.length(), L' ');
		std::copy(str.begin(), str.end(), wstr.begin());
		
		return wstr;
	}

	inline HMODULE gdl_Open(const char *plname)
	{
#if defined(_WIN32)  
		return LoadLibraryA(plname);
#else
		return dlopen(plname, RTLD_NOW | RTLD_LOCAL);
#endif  
	}

	inline void gdl_Close(HMODULE h)
	{
		if (h)
		{
#if defined(_WIN32)  
			FreeLibrary(h);
#else
			dlclose(h);
#endif  
		}
	}

	inline void *gdl_GetProc(HMODULE h, const char *pfname)
	{
		if (h)
		{
#if defined(_WIN32)  
			return (void *)GetProcAddress(h, pfname);
#else
			return dlsym(h, pfname);
#endif  
		}
		return NULL;
	}

	inline void gdl_GetLastErrorMsg(char *p, int size)
	{

#if defined(_WIN32)  
		_snprintf(p, size, "dll error(%u)", ::GetLastError());
#else 
		snprintf(p, size, "%s", dlerror());
#endif  

	}

private:

	std::string m_strMsg;
	std::string m_strDllName;
	HMODULE m_hModule;
};

#endif